package org.budo.freemarker.spring.mvc.view;

import java.io.IOException;
import java.io.Reader;
import java.io.StringReader;
import java.io.StringWriter;

import org.budo.freemarker.template.loader.wrapper.TemplateLoaderWrapper;
import org.budo.support.lang.util.IoUtil;
import org.budo.support.lang.util.StringUtil;
import org.budo.support.slf4j.Slf4j;
import org.budo.time.Time;
import org.slf4j.Logger;
import org.springframework.core.io.ResourceLoader;
import org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer;

import freemarker.cache.TemplateLoader;
import lombok.Getter;
import lombok.Setter;

/**
 * @author limingwei
 * @see org.budo.freemarker.spring.mvc.view.BudoFreeMarkerView
 * @see org.budo.freemarker.spring.mvc.view.BudoFreeMarkerViewResolver
 */
@Getter
@Setter
public class BudoFreeMarkerConfigurer extends FreeMarkerConfigurer {
    private static final Logger log = Slf4j.getLogger();

    /**
     * 是否将模板信息作为Html注释放在模板中, 方便开发调试时区分
     */
    private Boolean commentTemplateInfoAtHead = false;

    private Boolean commentTemplateInfoAtFoot = false;

    private String commentLeft = "<!-- ";

    private String commentRight = " -->";

    private ResourceLoader resourceLoader;

    public void setTemplateLoaderPaths(String... templateLoaderPaths) {
        log.info("setTemplateLoaderPaths, templateLoaderPaths=" + StringUtil.join(templateLoaderPaths));
        super.setTemplateLoaderPaths(templateLoaderPaths);
    }

    public ResourceLoader getResourceLoader() {
        if (null == resourceLoader) {
            synchronized (FreeMarkerConfigurer.class) {
                if (null == resourceLoader) {
                    return super.getResourceLoader();
                }
            }
        }
        return resourceLoader;
    }

    protected TemplateLoader superGetTemplateLoaderForPath(String templateLoaderPath) {
        return super.getTemplateLoaderForPath(templateLoaderPath);
    }

    protected TemplateLoader getTemplateLoaderForPath(final String templateLoaderPath) {
        TemplateLoader templateLoader = this.superGetTemplateLoaderForPath(templateLoaderPath);

        final ResourceLoader resourceLoader = this.getResourceLoader();
        log.info("getTemplateLoaderForPath, templateLoaderPath=" + templateLoaderPath //
                + ", templateLoader=" + templateLoader + ", resourceLoader=" + resourceLoader + ", resourceLoader.type=" + resourceLoader.getClass().getName());

        if (!this.getCommentTemplateInfoAtHead() && !this.getCommentTemplateInfoAtFoot()) {
            return templateLoader;
        }

        return new TemplateLoaderWrapper(templateLoader) {
            public Reader getReader(Object templateSource, String encoding) throws IOException {
                Reader reader = super.getReader(templateSource, encoding);

                StringWriter stringWriter = new StringWriter();
                IoUtil.write(reader, stringWriter);

                String commentLeft = BudoFreeMarkerConfigurer.this.getCommentLeft();
                String commentRight = BudoFreeMarkerConfigurer.this.getCommentRight();

                StringBuffer commentTemplateInfo = new StringBuffer() //
                        .append(commentLeft).append("templateLoaderPath: ").append(templateLoaderPath).append(commentRight).append("\n") //
                        .append(commentLeft).append("templateSource: ").append(templateSource).append(commentRight).append("\n") //
                        .append(commentLeft).append("templateSource.type: ").append(templateSource.getClass().getName()).append(commentRight).append("\n") //
                        .append(commentLeft).append("resourceLoader: ").append(resourceLoader).append(commentRight).append("\n") //
                        .append(commentLeft).append("resourceLoader.type: ").append(resourceLoader.getClass().getName()).append(commentRight).append("\n") //
                        .append(commentLeft).append("now: ").append(Time.now().toString("yyyy-MM-dd HH:mm:ss SSS")).append(commentRight) //
                        .append("");

                StringBuffer result = new StringBuffer();
                if (BudoFreeMarkerConfigurer.this.getCommentTemplateInfoAtHead()) {
                    result.append(commentTemplateInfo);
                    result.append("\n").append(commentLeft).append("↓↓↓ ↓↓↓ ↓↓↓").append(commentRight).append("\n\n");
                }

                result.append(stringWriter.getBuffer());

                if (BudoFreeMarkerConfigurer.this.getCommentTemplateInfoAtFoot()) {
                    result.append("\n\n").append(commentLeft).append("↑↑↑ ↑↑↑ ↑↑↑").append(commentRight).append("\n");
                    result.append(commentTemplateInfo);
                }

                return new StringReader(result.toString());
            }
        };
    }
}
